/*
 * Notify.java
 *
 * Created on 22 ������ 2007 �., 17:17
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package jimm.modules;

import java.util.*;
// #sijapp cond.if modules_ANDROID is "true" #
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import org.jimm.JimmActivity;
// #sijapp cond.else #
import javax.microedition.media.*;
import javax.microedition.media.control.*;
// #sijapp cond.end #
import java.io.InputStream;
import jimm.*;
import jimm.comm.Util;
import jimm.ui.base.Popup;
import jimm.util.*;

/**
 *
 * @author vladimir
 */
// #sijapp cond.if modules_SOUND is "true" #
public class Notify implements Runnable
        // #sijapp cond.if modules_ANDROID isnot "true" #
        , PlayerListener
        // #sijapp cond.else #
        , MediaPlayer.OnCompletionListener
        // #sijapp cond.end #
        {

    private static Notify _this = new Notify();

    public static Notify getSound() {
        return _this;
    }
    /* Notify notification typs */
    public static final int NOTIFY_MESSAGE = 0;
    public static final int NOTIFY_ONLINE = 1;
    public static final int NOTIFY_TYPING = 2;
    public static final int NOTIFY_MULTIMESSAGE = 3;
    public static final int NOTIFY_ALARM = 4;
    public static final int NOTIFY_RECONNECT = 5;
    public static final int NOTIFY_BLOG = 6;
    public static final int NOTIFY_OTHER = 7;   //other sound
    public static final int NOTIFY_OFFLINE = 8; //offline sound
    public static final int NOTIFY_EYE = 9;     //eye sound
    private long nextPlayTime = 0;
    private int playingType = 0;
    private String[] files = {null, null, null, null, null, null, null, null, null, null}; //changed
    private String fileVibrate = null;

    /**
     * Creates a new instance of Notify
     */
    private Notify() {
    }
    private String nextMelody = null;

    private String getMimeType(String ext) {
        if ("mp3".equals(ext)) {
            return "audio/mpeg";
        }
        if ("mid".equals(ext) || "midi".equals(ext)) {
            return "audio/midi";
        }
        if ("amr".equals(ext)) {
            return "audio/amr";
        }
        if ("mmf".equals(ext)) {
            return "audio/mmf";
        }
        if ("imy".equals(ext)) {
            return "audio/iMelody";
        }
        if ("aac".equals(ext)) {
            return "audio/aac";
        }
        if ("m4a".equals(ext)) {
            return "audio/m4a";
        }
        return "audio/X-wav"; // wav
    }

    // #sijapp cond.if modules_ANDROID is "true" #
    private class StopVibro extends TimerTask {

        public void run() {
            Notify.this.vibrate(0);
        }
    }
    // #sijapp cond.end #
    private void vibrate(int duration) {
        Jimm.getJimm().getDisplay().getNativeDisplay().vibrate(duration);
        // #sijapp cond.if modules_ANDROID is "true" #
        if (0 < duration) {
            new Timer().schedule(new StopVibro(), duration);
        }
        // #sijapp cond.end #
    }

    private int getVolume() {
        return Options.getInt(Options.OPTION_NOTIFY_VOLUME);
    }

    // Play a sound notification
    private boolean isSoundNotification(int notType) {
        switch (notType) {
            case NOTIFY_MESSAGE:
                return 0 < Options.getInt(Options.OPTION_MESS_NOTIF_MODE);

            case NOTIFY_ONLINE:
                return 0 < Options.getInt(Options.OPTION_ONLINE_NOTIF_MODE);
                
            case NOTIFY_OFFLINE:                                              //offline sound
                return 0 < Options.getInt(Options.OPTION_OFFLINE_NOTIF_MODE); //offline sound
                
            case NOTIFY_TYPING:                                         //typing sound 
                return 0 < Options.getInt(Options.OPTION_TYPING_MODES); //typing sound   

            case NOTIFY_BLOG:
                return Options.getBoolean(Options.OPTION_BLOG_NOTIFY);
                
            case NOTIFY_EYE:                                          //eye sound
                return Options.getBoolean(Options.OPTION_EYE_NOTIFY); //eye sound

            case NOTIFY_MULTIMESSAGE:
                return false;
                
              case NOTIFY_OTHER:                                            //other sound
                return 0 < Options.getInt(Options.OPTION_OTHER_NOTIF_MODE); //other sound              
        }
        return true;
    }

    private boolean isCompulsory(int notType) {
        switch (notType) {
            case NOTIFY_MESSAGE:
            case NOTIFY_MULTIMESSAGE:
            case NOTIFY_ALARM:
            case NOTIFY_BLOG:
            case NOTIFY_OTHER: //other sound
            case NOTIFY_EYE:   //eye sound    
                return true;
        }
        return false;
    }

    private void playNotify() {
        int notType = playingType;
        int vibrate = 0;
        if (NOTIFY_ALARM == notType) {
            vibrate = 1500;
        } else {

            int vibraKind = Options.getInt(Options.OPTION_VIBRATOR);
            if ((vibraKind == 2) && !Jimm.isLocked()) {
                vibraKind = 0;
            }
            if ((vibraKind > 0)
                    && ((NOTIFY_MESSAGE == notType) || (NOTIFY_MULTIMESSAGE == notType))) {
                vibrate(Util.strToIntDef(Options.getString(Options.OPTION_VIBRATOR_TIME), 200)); //vibra time
            }
        }

        String file = files[notType];

        boolean play = !Options.getBoolean(Options.OPTION_SILENT_MODE)
                && isSoundNotification(notType);

        if (0 < vibrate) {
            // #sijapp cond.if modules_ANDROID isnot "true" #
            if (null != fileVibrate) {
                if (play && (null != file)) {
                    nextMelody = file;
                    play = false;
                }
                play(fileVibrate);
                return;
            }
            // #sijapp cond.end#
            vibrate(vibrate);
        }

        if (play) {
            if (null == file) {
                // #sijapp cond.if modules_ANDROID isnot "true" #
                if (NOTIFY_MESSAGE == notType) {
                    try {
                        Manager.playTone(ToneControl.C4, 750, getVolume());
                    } catch (Exception e) {
                    }
                }
                // #sijapp cond.end#
                return;
            }
            play(file);
        }
    }
    // #sijapp cond.if modules_ANDROID is "true" #
    @Override
    public void onCompletion(MediaPlayer mp) {
        mp.release();
    }
    // #sijapp cond.end#

    private void closePlayer() {
        // #sijapp cond.if modules_ANDROID is "true" #
        if (null != androidPlayer) {
            androidPlayer.release();
            androidPlayer = null;
        }
        // #sijapp cond.else #
        if (null != j2mePlayer) {
            try {
                j2mePlayer.stop();
            } catch (Exception e) {
            }
            try {
                j2mePlayer.close();
            } catch (Exception e) {
            }
            j2mePlayer = null;
        }
        // #sijapp cond.end #
    }
    public void run() {
        try {
            playNotify();
        } catch (OutOfMemoryError err) {
        }
    }
    private synchronized void playNotification(int notType) {
        final long now = System.currentTimeMillis();
        if (!isCompulsory(playingType) && isCompulsory(notType)) {
            nextPlayTime = 0;
        }
        if (now < nextPlayTime) {
            return;
        }
        if (NOTIFY_ALARM == notType) {
            if (!Options.getBoolean(Options.OPTION_ALARM)) {
                return;
            }
            nextPlayTime = now + 3000;

        } else {
            nextPlayTime = now + 2000;
        }
        playingType = notType;
        new Thread(this).start();
    }

    public void playSoundNotification(int notType) {
        playNotification(notType);
    }
    // #sijapp cond.if modules_ANDROID isnot "true" #
    private Player j2mePlayer;
    // #sijapp cond.else#
    private MediaPlayer androidPlayer;
    // #sijapp cond.end#

    // #sijapp cond.if modules_ANDROID isnot "true" #
    public void playerUpdate(final Player player, final String event, Object eventData) {
        if (event.equals(PlayerListener.END_OF_MEDIA)) {
            closePlayer();
            String next = nextMelody;
            if (null != next) {
                nextMelody = null;
                play(next);
            }
        }
    }
    // #sijapp cond.end #

    private boolean testSoundFile(String source) {
        Notify notify = new Notify();
        notify.createPlayer(source);
        boolean ok;
        // #sijapp cond.if modules_ANDROID isnot "true" #
        ok = (null != notify.j2mePlayer);
        // #sijapp cond.else#
        ok = (null != notify.androidPlayer);
        // #sijapp cond.end#
        notify.closePlayer();
        return ok;
    }

    /* Creates player for file 'source' */
    private void createPlayer(String source) {
        closePlayer();
        try {
            // #sijapp cond.if modules_ANDROID isnot "true" #
            /* What is file extention? */
            String ext = source.substring(source.lastIndexOf('.') + 1);

            InputStream is = jimm.Jimm.getResourceAsStream(source);
            if (null != is) {
                j2mePlayer = Manager.createPlayer(is, getMimeType(ext));
                j2mePlayer.addPlayerListener(this);
            }
            // #sijapp cond.else #
            AssetFileDescriptor afd = JimmActivity.getInstance().getAssets().openFd(source.substring(1));
            androidPlayer = new MediaPlayer();
            androidPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            androidPlayer.prepare();
            // #sijapp cond.end #
        } catch (Exception e) {
            closePlayer();
        }
    }

    private void play(String file) {
        createPlayer(file);
        try {
            // #sijapp cond.if modules_ANDROID isnot "true" #
            j2mePlayer.realize();
            try {
                int volume = getVolume();
                VolumeControl c = (VolumeControl) j2mePlayer.getControl("VolumeControl");
                if ((null != c) && (0 < volume)) {
                    c.setLevel(volume);
                }
            } catch (Exception e) {
            }
            j2mePlayer.prefetch();
            j2mePlayer.start();
            // #sijapp cond.else #
            androidPlayer.setOnCompletionListener(this);
            androidPlayer.start();
            // #sijapp cond.end #

        } catch (Exception e) {
            closePlayer();
        }
    }

    private String selectSoundType(String name) {
        /* Test other extensions */
        String[] exts = Util.explode("mp3|wav|mid|midi|mmf|amr|imy|aac|m4a", '|');
        for (int i = 0; i < exts.length; ++i) {
            String testFile = name + exts[i];
            if (testSoundFile(testFile)) {
                return testFile;
            }
        }
        return null;
    }

    public void changeSoundMode(boolean showPopup) {
        boolean newValue = !Options.getBoolean(Options.OPTION_SILENT_MODE);
        if (showPopup) {
            String text = newValue ? "#sound_is_off" : "#sound_is_on";
            new Popup(JLocale.getString(text)).show();
        }
        vibrate(newValue ? 0 : 100);
        closePlayer();
        Options.setBoolean(Options.OPTION_SILENT_MODE, newValue);
        Options.safeSave();
    }

    public void initSounds() {
        files[NOTIFY_ONLINE] = selectSoundType("/online.");
        files[NOTIFY_OFFLINE]  = selectSoundType("/offline."); //offline sound
        files[NOTIFY_MESSAGE] = selectSoundType("/message.");
        files[NOTIFY_TYPING] = selectSoundType("/typing.");
        files[NOTIFY_ALARM] = selectSoundType("/alarm.");
        files[NOTIFY_RECONNECT] = selectSoundType("/reconnect.");
        files[NOTIFY_BLOG] = selectSoundType("/blog.");
        files[NOTIFY_OTHER]   = selectSoundType("/other."); //other sound
        files[NOTIFY_EYE] = selectSoundType("/eye."); //eye sound
        if (testSoundFile("/vibrate.imy")) {
            fileVibrate = "/vibrate.imy";
        }
    }

    public boolean hasAnySound() {
        for (int i = 0; i < files.length; ++i) {
            if (null != files[i]) {
                return true;
            }
        }
        return false;
    }
}
// #sijapp cond.end #
